
// === uuMsg ===
// depend: none
/*
uuMsg.prototype.regist(obj, ...) - return this
uuMsg.prototype.unregist(obj, ...) - return this
uuMsg.prototype.send(to, msg, p1, p2) - return msgbox() result value
uuMsg.prototype.post(to, msg, p1, p2) - return this
 */

(function() {
var _msg, // inner namespace
    UNIQUE_ID = "uuid";

_msg = function() {
  this._addr = { /* UNIQUE_ID: obj, ... */ };
  this._msg = [ /* num: [ UNIQUE_ID, msg, param1, param2], ... */ ];
  this._run = 0;
};

_msg.prototype = {
  // uuMsg.prototype.regist - register the destination of the message
  regist:
      function(obj,        // @param Object: object has UNIQUE_ID property
               var_args) { // @param Object(= undefined):
                           // @return this:
    var arg = arguments, v, i = 0, iz = arg.length;

    for (; i < iz; ++i) {
      v = arg[i];
      if (!v[UNIQUE_ID]) { throw ""; }
      this._addr[v[UNIQUE_ID]] = v;
    }
    return this;
  },

  // uuMsg.prototype.unregist
  unregist:
      function(obj,        // @param Object: object has UNIQUE_ID property
               var_args) { // @param Object(= undefined):
                           // @return this:
    var arg = arguments, v, i = 0, iz = arg.length;

    for (; i < iz; ++i) {
      v = arg[i];
      if (!v[UNIQUE_ID]) { throw ""; }
      delete this._addr[obj[UNIQUE_ID]];
    }
    return this;
  },

  // uuMsg.prototype.send - send a message synchronously
  send: function(to,   // @param Object: send to
                 msg,  // @param String: msg
                 p1,   // @param Mix(= undefined): param1
                 p2) { // @param Mix(= undefined): param2
                       // @return Mix: msgbox() result value
    var rv = [], v, i, iz, ary;

    if (to) { // unicast, multicast
      ary = (to instanceof Array) ? to : [to];
      for (i = 0, iz = ary.length; i < iz; ++i) {
        v = ary[i];
        rv.push(this._addr[typeof v === "object" ? v[UNIQUE_ID]
                                                 : v].msgbox(msg, p1, p2));
      }
      // if it is an unicast, not the array but the return value is returned.
      return (rv.length === 1) ? rv[0] : rv;
    }
    // broadcast
    for (i in this._addr) {
      rv.push(this._addr[i].msgbox(msg, p1, p2));
    }
    return rv;
  },

  // uuMsg.prototype.post - send a message asynchronously
  post: function(to,   // @param Object: send to
                 msg,  // @param String: msg
                 p1,   // @param Mix(= undefined): param1
                 p2) { // @param Mix(= undefined): param2
                       // @return this:
    var stock = this._msg, v, i, iz, ary;

    if (to) { // unicast, multicast
      ary = (to instanceof Array) ? to : [to];
      for (i = 0, iz = ary.length; i < iz; ++i) {
        v = ary[i];
        stock.push([typeof v === "object" ? v[UNIQUE_ID] : v, msg, p1, p2]);
      }
    } else { // broadcast
      for (i in this._addr) {
        stock.push([i, msg, p1, p2]);
      }
    }
    this._runner();
    return this;
  },

  _runner: function() {
    var me = this, lp;

    lp = function() {
      if (!me._msg.length) {
        me._run = 0;
        return;
      }
      var v = me._msg.shift();
      if (v[0] in me._addr) {
        me._addr[v[0]].msgbox(v[1], v[2], v[3]); // (msg, param1, param2)
      }
      me._run = 1;
      setTimeout(lp, 0);
    };

    !this._run && lp();
  }
});

// --- initialize ---

// --- export ---
window.uuMsg = new _msg(); // window.uuMsg is instance

})(); // uuMsg scope
